package com.miplus.ccrm.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miplus.ccrm.admin.controller.vo.*;
import com.miplus.ccrm.admin.mapper.*;
import com.miplus.ccrm.admin.pojo.*;
import com.miplus.ccrm.admin.security.JwtToken;
import com.miplus.ccrm.admin.service.SysDeviceHistService;
import com.miplus.ccrm.admin.service.SysUserService;
import com.miplus.ccrm.admin.utils.SpringContextUtil;
import com.miplus.ccrm.common.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
* @author pc
* @description 针对表【sys_user(系统用户表)】的数据库操作Service实现
* @createDate 2024-02-22 20:28:53
*/
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
    implements SysUserService{

    @Value("${aes.key}")
    private String aesKey;

    @Resource
    private JDataService dataService;

    @Resource
    private SysGrpMapper sysGrpMapper;

    @Resource
    private SysDeviceHistService sysDeviceHistService;

    private SysAuditLogMapper sysAuditLogMapper;

    private SysUrlinkMapper sysUrlinkMapper;

    private SysGrpmgrMapper sysGrpmgrMapper;

    @Autowired
    public void setSysAuditLogMapper(SysAuditLogMapper s) {
        sysAuditLogMapper=s;
    }

    @Autowired
    public void setSysUrlinkMapper(SysUrlinkMapper s) {
        sysUrlinkMapper=s;
    }

    @Autowired
    public void setSysGrpmgrMapper(SysGrpmgrMapper s) {
        sysGrpmgrMapper=s;
    }

    @Override
    public UserSignInResVo doSignIn(UserSignInReqVo userSignInReqVo,String reqIpAddr)
    {
        //TDSQL里面的groups是关键字，必须前面要加一个表别名,否则出错
        //SysUser user = getById(userSignInReqVo.getUsername());
        log.info("doSignIn({})..",userSignInReqVo.getUsername());
        SysUser user=getBaseMapper().getUser(userSignInReqVo.getUsername());
        if(user==null||(!JPubUtils.IsEqual(user.getStatus(),"1")))
            throw new ServiceException(EnumRCode.NoFindUsr.value, EnumRCode.NoFindUsr.name);

        if(JPubUtils.IsEqual(user.getIslocked(),"1") && user.getLocktime() != null && user.getLocktime().compareTo(new Date()) != -1)
            throw new ServiceException(EnumRCode.UsrLocked.value, EnumRCode.UsrLocked.name);

        SysUser upuser=new SysUser();
        upuser.setUsrid(user.getUsrid());
        String inpwd=JSecurity.aesDecode(userSignInReqVo.getPassword(),aesKey);
        if(!JSecurity.encoderMatches(inpwd,user.getPassword())) {
            int failcc=1;
            if(!JPubUtils.IsEmpty(user.getFailtimes())){
                failcc=user.getFailtimes()+1;
            }
            upuser.setFailtimes(failcc);
            if(failcc>=JPubUtils.login_maxfailtimes){
                upuser.setIslocked("1");
                upuser.setLocktime(JPubUtils.addMinute(new Date(),JPubUtils.login_failLockSapn));
            }
            updateById(upuser);
            throw new ServiceException(EnumRCode.PwdError.value, EnumRCode.PwdError.name);
        }

        if(JPubUtils.IsNotEmpty(user.getGroups())){
            SysGrp grp= sysGrpMapper.selectById(user.getGroups());
            if(JPubUtils.IsEqual(grp.getGrplevel(),"1")){//需要短信验证码
                String code=userSignInReqVo.getCode();
                if(JPubUtils.IsEmpty(code)){
                    throw new ServiceException(EnumRCode.VCodeNull.value, EnumRCode.VCodeNull.name);
                }
                String idenfyCode="";
                String vcodeiden=JPubUtils.getVCodeIden(user.getUsrid());
                if(dataService.hasKey(vcodeiden)){
                    idenfyCode=(String)dataService.get(vcodeiden);
                }else{
                    log.warn("doSignIn({}):NoFind VCode",user.getUsrid());
                }
                if(!JPubUtils.IsEqual(idenfyCode,code)){
                    throw new ServiceException(EnumRCode.VCodeFail.value, EnumRCode.VCodeFail.name);
                }
            }
        }

        upuser.setFailtimes(0);
        upuser.setIslocked("0");

        //2024-07-22
        //upuser.setLocktime(null);
        //updateById(upuser);
        baseMapper.update(upuser,new UpdateWrapper<SysUser>()
                .lambda()
                .eq(SysUser::getUsrid,user.getUsrid())
                .set(SysUser::getLocktime,null)
        );

        String token = JwtToken.build(
                JPubUtils.jwt_Secret,
                JPubUtils.jwt_expiration,
                userSignInReqVo.getUsername()
        );

        log.info("SignIn({}).Ok:expiration={},allowdefaultpwd={},token={}",
                userSignInReqVo.getUsername(),
                JPubUtils.jwt_expiration,
                JPubUtils.login_allowdefaultpwd,
                token
        );

        insertAuditLog(user.getUsrid(),user.getUsrid(),3,"签入成功");

        String oldtoken=(String)dataService.get(JPubUtils.getOnlineTokenKey(user.getUsrid()));
        if(oldtoken!=null){//del pre login token
            String tokenkey=JPubUtils.getTokenKey(oldtoken);
            if (dataService.hasKey(tokenkey)) {
                log.info("delToken:{}",oldtoken);
                dataService.del(tokenkey);
            }
        }
        JSysUser jSysUser=new JSysUser();
        BeanUtils.copyProperties(user,jSysUser);
        jSysUser.setIsdefaultpwd("0");

        UserSignInResVo resVo=new UserSignInResVo();
        resVo.setIsdefaultpwd("0");

        if(!JPubUtils.login_allowdefaultpwd){
            if(JSecurity.encoderMatches(JPubUtils.login_defaultpwd,user.getPassword())){
                log.info("SignIn({}).login defaultpwd",user.getUsrid());
                resVo.setIsdefaultpwd("1");
                jSysUser.setIsdefaultpwd("1");
            }
        }

        if (!JPubUtils.IsEqual(resVo.getIsdefaultpwd(),"1")) {
            log.info("SignIn({}).login setPermission",user.getUsrid());
            List<String> ps = getBaseMapper().getPermissionByUsrId(user.getUsrid());
            jSysUser.setPermlist(ps);
        }
        //增加管理组，20250507
        List<String> mgrgrps = getBaseMapper().getMgrGrpId(user.getUsrid());
        jSysUser.setMgrgrplist(mgrgrps);

        dataService.set(JPubUtils.getTokenKey(token), jSysUser, JPubUtils.jwt_expiration);

        //为了保证同一个账号只允许一个在线
        dataService.set(JPubUtils.getOnlineTokenKey(user.getUsrid()), token, JPubUtils.jwt_expiration);

        resVo.setType("Bearer");
        resVo.setUsername(userSignInReqVo.getUsername());
        resVo.setToken(token);
        resVo.setExpires_in(JPubUtils.jwt_expiration);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        resVo.setToken_crdt(sdf.format(new Date()));

        return resVo;
    }

    @Override
    public EnumRCode doSignDown(String token)
    {
        String tokenkey=JPubUtils.getTokenKey(token);
        if (dataService.hasKey(tokenkey)) {
            log.info("doSignDown:{}",token);
            JSysUser user = (JSysUser) dataService.get(tokenkey);
            if (dataService.hasKey(tokenkey)) {
                dataService.del(tokenkey);
            }
            if (dataService.hasKey(JPubUtils.getOnlineTokenKey(user.getUsrid()))) {
                dataService.del(JPubUtils.getOnlineTokenKey(user.getUsrid()));
            }
            if (dataService.hHasKey("userGetusrinfo", "{$usrid=" + user.getUsrid() + "}")) {
                dataService.hdel("userGetusrinfo", "{$usrid=" + user.getUsrid() + "}");
            }
            if (dataService.hHasKey("permission", "{$usrid=" + user.getUsrid() + "}")) {
                dataService.hdel("permissions", "{$usrid=" + user.getUsrid() + "}");
            }

            insertAuditLog(user.getUsrid(),user.getUsrid(),12,"签出成功");
        }
        return EnumRCode.Success;
    }

    @Override
    public UserInfoResVo quyUserInfo(String usrid,boolean isedit)
    {
        //log.info("quyUserInfo:{},isedit={}",usrid,isedit);
        //SysUser user = getById(usrid);
        SysUser user=getBaseMapper().getUser(usrid);
        //if(user==null||(!JPubUtils.IsEqual(user.getStatus(),"1"))){
        //否则禁用时，点修改出错
        //    return null;
        //}
        UserInfoResVo resVo=new UserInfoResVo();
        resVo.setUsrid(usrid);
        resVo.setStatus(user.getStatus());
        resVo.setAdapter(user.getAdapter());
        resVo.setEmail(user.getEmail());
        resVo.setExt(user.getExt());
        resVo.setAgentid(user.getAgentid());
        resVo.setAgentpwd(user.getAgentpwd());
        resVo.setEmployeeid(user.getEmployeeid());
        resVo.setGrpid(user.getGroups());
        resVo.setHeadimg(user.getHeadimg());
        resVo.setMobile(user.getMobile());
        resVo.setName(user.getName());
        resVo.setTenantid(user.getTenantid());
        resVo.setTheme(user.getTheme());
        resVo.setTitle(user.getTitle());
        resVo.setKey(usrid);

        if(isedit){
            HashMap<String, Object> mp=getBaseMapper().getRoleMgrGroup(usrid);
            if(mp!=null) {
                resVo.setRole((String) mp.get("role"));
                resVo.setMgrgrp((String) mp.get("mgrgrp"));

            }
        }
        else {
            List<String> ps = getBaseMapper().getPermissionByUsrId(usrid);
            resVo.setPermissions(ps);
        }

        return resVo;
    }

    @Override
    public IPage<UserInfoResVo> systemUserSelect(UserInfoReqVo paras, String usrid)
    {
        return baseMapper.systemUserSelect(new Page<>(paras.getPageNum(), paras.getPageSize()),usrid,paras);
    }

    @Override
    @Transactional
    public CmdResVo updateUser(String userid,UserEditReqVo paras)
    {
        log.info("updateUser({}):{}",userid,paras.getUsrid());
        SysUser sysUser = getById(paras.getUsrid());
        if(sysUser == null)
            return new CmdResVo(-1,"没有找到用户");

        if(StringUtils.isNotEmpty(paras.getExt())){
            if(sysDeviceHistService.checkValidDevice(paras.getUsrid(),paras.getExt()) > 0L) {
                log.info(" device<{} >fail。has exists.", paras.getExt());
                throw new ServiceException(EnumRCode.CmdFail.value, "分机已分配给其他用户");
            }
        }
        SysUser user=new SysUser();
        BeanUtils.copyProperties(paras,user);
        //user.setGroups(paras.getGrpid()); //2024-07-22 for TDSQL
        user.setGroups(paras.getGrpid());
        user.setMdusr(userid);
        user.setMddt(new Date());
        int ret=baseMapper.updateById(user);
        if(ret>0) {
            baseMapper.updateGroups(paras.getUsrid(),paras.getGrpid());

            if(paras.getAddRole()!=null||paras.getRemoveRole()!=null) {
                sysUrlinkMapper.delete(
                        new QueryWrapper<SysUrlink>().eq("usrid", paras.getUsrid())
                );
                for (String role : paras.getRole()) {
                    SysUrlink ul = new SysUrlink();
                    ul.setUsrid(paras.getUsrid());
                    ul.setRoleid(role);
                    sysUrlinkMapper.insert(ul);
                }
            }

            if(paras.getAddMgrGrp()!=null||paras.getRemoveMgrGrp()!=null) {
                sysGrpmgrMapper.delete(
                        new QueryWrapper<SysGrpmgr>().eq("grpmanagerid", paras.getUsrid())
                );
                for (String grp : paras.getMgrgrp()) {
                    SysGrpmgr mg = new SysGrpmgr();
                    mg.setGrpid(grp);
                    mg.setGrpmanagerid(paras.getUsrid());
                    mg.setCrdt(new Date());
                    mg.setCrusr(userid);
                    sysGrpmgrMapper.insert(mg);
                }
            }
        }
        if(StringUtils.isNotEmpty(sysUser.getExt()) && StringUtils.isEmpty(user.getExt()))
            sysDeviceHistService.endDevice(user.getUsrid(),sysUser.getExt());
        else if(StringUtils.isNotEmpty(sysUser.getExt()) && !user.getExt().equals(sysUser.getExt()))
        {
            sysDeviceHistService.endDevice(user.getUsrid(),sysUser.getExt());
            if("1".equals(sysUser.getStatus()))
                sysDeviceHistService.startDevice(user.getGroups(),user.getUsrid(),user.getExt());
        }
        else if(StringUtils.isEmpty(sysUser.getExt()) && StringUtils.isNotEmpty(user.getExt()))
        {
            if("1".equals(sysUser.getStatus()))
                sysDeviceHistService.startDevice(user.getGroups(),user.getUsrid(),user.getExt());
        }
        return new CmdResVo(ret);
    }

    @Override
    @Transactional
    public CmdResVo deleteUser(String userid,UserIDReqVo paras)
    {
        log.info("deleteUser({}):{}",userid,paras.getUsrid());
        SysUser sysUser = getById(paras.getUsrid());
        sysUrlinkMapper.delete(
                new QueryWrapper<SysUrlink>().eq("usrid",paras.getUsrid())
        );
        sysGrpmgrMapper.delete(
                new QueryWrapper<SysGrpmgr>().eq("grpmanagerid",paras.getUsrid())
        );

        int ret=baseMapper.deleteById(paras.getUsrid());

        insertAuditLog(userid,paras.getUsrid(),7,"删除用户");
        if(sysUser != null )
            sysDeviceHistService.endDevice(paras.getUsrid(),sysUser.getExt());
        return new CmdResVo(ret);
    }

    @Override
    @Transactional
    public CmdResVo insertUser(String userid,UserEditReqVo paras){
        //for TDSQL
        //SysUser user=baseMapper.selectById(paras.getUsrid());
        SysUser user=baseMapper.getUser(paras.getUsrid());
        if(user!=null){//2024-05-31
            log.info("insertUser({}):HasExist",paras.getUsrid());
            throw new ServiceException(EnumRCode.UsrExist.value, EnumRCode.UsrExist.name);
        }

        log.info("insertUser({}):{}",userid,paras.getUsrid());
        if(StringUtils.isNotEmpty(paras.getExt())){
           if(sysDeviceHistService.checkValidDevice(paras.getUsrid(),paras.getExt()) > 0L) {
               log.info(" device<{} >fail。has exists.", paras.getExt());
               throw new ServiceException(EnumRCode.CmdFail.value, "分机已分配给其他用户");
           }
        }
        user=new SysUser();
        BeanUtils.copyProperties(paras,user);
        //user.setGroups(paras.getGrpid()); //for TDSQL,2024-07-22
        user.setCrusr(userid);
        user.setCrdt(new Date());
        user.setMdusr(userid);
        user.setMddt(new Date());
        //增加初始状态和时间。20250611
        user.setStatus("1");
        user.setStatusdt( new Date());
        String pwd=SpringContextUtil.getUserInitPwd();
        pwd=JSecurity.md5Encryption(pwd);
        user.setPassword(pwd);
        user.setGroups(paras.getGrpid());
        int ret=baseMapper.insert(user);
        if(ret>0){
            baseMapper.updateGroups(paras.getUsrid(),paras.getGrpid());

            if(JPubUtils.IsNotEmpty(paras.getRole())) {
                for (String role : paras.getRole()) {
                    SysUrlink ul = new SysUrlink();
                    ul.setUsrid(paras.getUsrid());
                    ul.setRoleid(role);
                    sysUrlinkMapper.insert(ul);
                }
            }

            if(JPubUtils.IsNotEmpty(paras.getMgrgrp())) {
                for (String grp : paras.getMgrgrp()) {
                    SysGrpmgr mg = new SysGrpmgr();
                    mg.setGrpid(grp);
                    mg.setGrpmanagerid(paras.getUsrid());
                    mg.setCrdt(new Date());
                    mg.setCrusr(userid);
                    sysGrpmgrMapper.insert(mg);
                }
            }

            insertAuditLog(userid,paras.getUsrid(),1,"新建用户");
        }else{
            throw new ServiceException(EnumRCode.CmdFail.value, EnumRCode.CmdFail.name);
        }
        //增加分机
        if(StringUtils.isNotEmpty(user.getExt())){
            CmdResVo r = sysDeviceHistService.startDevice(user.getGroups(),user.getUsrid(),user.getExt());
        }
        return new CmdResVo(ret);
    }

    @Override
    public CmdResVo resetPassword(String userid,UserReqVo paras)
    {
        String pwd=SpringContextUtil.getUserInitPwd();
        pwd=JSecurity.md5Encryption(pwd);
        if(JPubUtils.IsEmpty(pwd))
            throw new ServiceException(EnumRCode.EcryErr.value, EnumRCode.EcryErr.name);

        int ret=doUpdate(userid,paras.getUsrid(),4,pwd,"密码被重置");

        return new CmdResVo(ret);
    }

    private int doUpdate(String $usrid,String userid,int action,String val,String valdec)
    {
        log.info("doUpdate({}):Operator={},action={},val={},{}",userid,$usrid, action,val,valdec);

        SysUser user=new SysUser();
        user.setUsrid(userid);
        user.setMdusr($usrid);
        user.setMddt(new Date());

        if(action==4||action==2) {
            user.setPassword(val);
        }
        else if(action==5||action==6) {
            user.setStatus(val);
            user.setStatusdt( new Date());
        }
        user.setPwdExpiration(JPubUtils.addMonths(new Date(),3));

        //int ret=baseMapper.updateById(user);
        int ret=baseMapper.update(user,new UpdateWrapper<SysUser>()
                .lambda()
                .eq(SysUser::getUsrid,user.getUsrid())
                .set(SysUser::getFailtimes,0)
                .set(SysUser::getIslocked,"0")
                .set(SysUser::getLocktime,null)
        );
        insertAuditLog($usrid,userid,action,valdec);

        return ret;
    }

    private void insertAuditLog(String $usrid,String userid,int action,String remark)
    {
        SysAuditLog log = new SysAuditLog();
        log.setAction(String.valueOf(action));
        log.setRemark(remark);
        log.setOperator($usrid);
        log.setTarget(userid);
        log.setAddress(JPubUtils.getReqIpAddr());
        log.setCrdt(new Date());
        sysAuditLogMapper.insert(log);
    }

    @Override
    public CmdResVo updatePwd(String userid,UserUpdatePwdVo paras)
    {
        String password = JSecurity.aesDecode(paras.getPassword(), aesKey);
        String oldPassword = JSecurity.aesDecode(paras.getOldpassword(), aesKey);
        String pwd = baseMapper.getPwd(userid);
        if(!JSecurity.encoderMatches(oldPassword,pwd))
            throw new ServiceException(EnumRCode.PwdError.value, EnumRCode.PwdError.name);

        password = JSecurity.md5Encryption(password);
        int ret=doUpdate(userid,userid,2,password,"修改密码");

        return new CmdResVo(ret);
    }

    @Override
    public CmdResVo updateStatus(String userid,UserReqVo paras)
    {
        int ret=0;
        SysUser sysUser = getById(paras.getUsrid());
        if(sysUser == null)
            return new CmdResVo(-1,"没有找到相应的用户");
        if(JPubUtils.IsEqual(paras.getStatus(),"1")){
            ret=doUpdate(userid,paras.getUsrid(),6,"1","启用用户");
            sysDeviceHistService.startDevice(sysUser.getGroups(),sysUser.getUsrid(),sysUser.getExt());
        }
        else{
            ret=doUpdate(userid,paras.getUsrid(),5,"0","停用用户");
            sysDeviceHistService.endDevice(sysUser.getUsrid(),sysUser.getExt());
        }
        return new CmdResVo(ret);
    }

    @Override
    public List<NamesResVo> getActiveUserList(String grpid)
    {
        return baseMapper.getActiveUserList(grpid);
    }

    @Override
    public List<GrpUserResVo> groupUserList(String userid) {

        return baseMapper.groupUserList(userid);
    }
}




